package com.nafets;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class SimpleGameModel {
	private int stringCount;
	private int fretCount;
	private GuitarString[] strings;
	private Tone tone;
	private State state;
	private Random random;
	
	private Set<NeckPosition> tonesToFind;
	private Set<NeckPosition> correct;
	private Set<NeckPosition> incorrect;

	public SimpleGameModel(int stringCount, int fretCount, GuitarString[] strings) {
		this.stringCount = stringCount;
		this.fretCount = fretCount;
		this.strings = strings;
		this.random = new Random();
		this.state = State.UNKNOWN;
	}
	
	public Tone startGame() {
		state = State.GAME_IN_PROGRESS;
		tonesToFind = new HashSet<NeckPosition>();
		correct = new HashSet<NeckPosition>();
		incorrect = new HashSet<NeckPosition>();
		
		tone = Tone.values()[random.nextInt(Tone.values().length)];
		for (int i = 0; i < strings.length; i++) {
			GuitarString string = strings[i];
			for (int j = 1; j <= fretCount; j++) {
				int currentTone = string.getToneAt(j);
				if (currentTone == tone.getToneValue()) {
					tonesToFind.add(new NeckPosition(i, j));
				}
			}
		}
		
		return tone;
	}
	
	public void selectTone(int stringIndex, int fretIndex) {
		if (state.equals(State.GAME_FINISHED)) {
			return;
		}
		
		NeckPosition pos = new NeckPosition(stringIndex, fretIndex);
		if (tonesToFind.contains(pos)) {
			correct.add(pos);
		} else {
			incorrect.add(pos);
		}
	}
	
	public void deselectTone(int stringIndex, int fretIndex) {
		if (state.equals(State.GAME_FINISHED)) {
			return;
		}
		
		NeckPosition pos = new NeckPosition(stringIndex, fretIndex);
		correct.remove(pos);
		incorrect.remove(pos);
	}
	
	public boolean endGame() {
		state = State.GAME_FINISHED;
		boolean result = (correct.size() == tonesToFind.size()) && (incorrect.size() == 0) ? true : false;
		return result;
	}

	public GuitarString getString(int i) {
		if (i < 0 || i >= stringCount) {
			throw new IllegalArgumentException(String.format(
					"Invalid argument [%d]. Ask for a fret between [0] and [%d]", i, fretCount));
		}
		
		return strings[i];
	}

	public int getToneAt(int stringIndex, int fretIndex) {
		if (stringIndex < 0 || fretIndex < 0 || stringIndex >= stringCount || fretIndex > fretCount) {
			throw new IllegalArgumentException(String.format(
					"Your argument is invalid. String index = [%d]; Fret index = [%d]", stringIndex, fretIndex));
		}
		
		return strings[stringIndex].getToneAt(fretIndex);
	}
	
	public Tone toneToGuess() {
		return tone;
	}

	public Set<NeckPosition> getTonesToFind() {
		return tonesToFind;
	}

	public Set<NeckPosition> getCorrect() {
		return correct;
	}

	public Set<NeckPosition> getIncorrect() {
		return incorrect;
	}

	public State getState() {
		return state;
	}
	
}
